﻿using System;
using System.ComponentModel;
using System.Diagnostics.Contracts;
using System.Net;
using System.Windows.Forms;

namespace GetThis_Server.Users
{
    public partial class UsersForm : Form
    {
        #region Fields

        private readonly string m_dataPath;

        private readonly Data m_data;

        private readonly Action<string> m_log;

        private Data.UserRow m_user;

        #endregion

        #region Constructors

        public UsersForm(string dataPath, Data data, Action<string> log)
        {
            Contract.Requires<ArgumentNullException>(!String.IsNullOrWhiteSpace(dataPath));
            Contract.Requires<ArgumentNullException>(data != null);
            Contract.Requires<ArgumentNullException>(log != null);

            m_dataPath = dataPath;
            m_data = data;
            m_log = log;
            InitializeComponent();
            Reload();
        }

        #endregion

        #region Events

        private void btnReload_Click(object sender, EventArgs e)
        {
            lstUsers.DataSource = null;
            m_data.Clear();
            m_data.ReadXml(m_dataPath);
            Reload();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            m_data.TrySave();
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            Contract.Assume(m_data.User != null);
            m_data.User.AddUserRow(Constants.UserNameDefaultValue, Constants.UserIpDefaultValue, Constants.UserKeyDefaultValue, Constants.UserAuthorizationDurationDefaultValue, Constants.UserBypassIpDefaultValue,
                Constants.UserBypassKeyDefaultValue);
            lstUsers.SelectedIndex = m_data.User.Count - 1;
        }

        private void btnRemove_Click(object sender, EventArgs e)
        {
            var index = lstUsers.SelectedIndex;
            Contract.Assume(m_data.User != null);
            var user = m_data.User.FindByName(txtName.Text);
            if (user != null)
                user.Delete();
            lstUsers.ClearSelected();
            if (lstUsers.Items.Count > 0)
                lstUsers.SelectedIndex = index;
            else
            {
                txtName.Clear();
                txtIp.Clear();
                chkBypassIp.Checked = false;
                txtKey.Clear();
                chkBypassKey.Checked = false;
                txtDays.Clear();
                txtHours.Clear();
                txtMinutes.Clear();
                txtSeconds.Clear();
            }
        }

        private void lstUsers_SelectedValueChanged(object sender, EventArgs e)
        {
            Contract.Assume(m_data.User != null);
            m_user = m_data.User.FindByName(lstUsers.SelectedValue as string);
            if (m_user != null)
            {
                txtName.Text = m_user.Name;
                txtIp.Text = m_user.Ip;
                chkBypassIp.Checked = m_user.BypassIp;
                txtKey.Text = m_user.Key;
                chkBypassKey.Checked = m_user.BypassKey;
                txtDays.Text = m_user.AuthorizationDuration.Days.ToString();
                txtHours.Text = m_user.AuthorizationDuration.Hours.ToString();
                txtMinutes.Text = m_user.AuthorizationDuration.Minutes.ToString();
                txtSeconds.Text = m_user.AuthorizationDuration.Seconds.ToString();
            }
        }

        private void txtName_Validating(object sender, CancelEventArgs e)
        {
            if (String.IsNullOrWhiteSpace(txtName.Text))
                e.Cancel = true;
            else if (m_user != null)
                m_user.Name = txtName.Text;
        }

        private void txtIp_Validating(object sender, CancelEventArgs e)
        {
            try
            {
                if (String.IsNullOrWhiteSpace(txtIp.Text) || Dns.GetHostAddresses(txtIp.Text).Length == 0)
                    e.Cancel = true;
                else if (m_user != null)
                    m_user.Ip = txtIp.Text;
            }
            catch (SystemException)
            {
                e.Cancel = true;
            }
        }

        private void chkBypassIp_CheckStateChanged(object sender, EventArgs e)
        {
            if (m_user != null)
                m_user.BypassIp = chkBypassIp.Checked;
        }

        private void txtKey_Validating(object sender, CancelEventArgs e)
        {
            if (String.IsNullOrWhiteSpace(txtKey.Text))
                e.Cancel = true;
            else if (m_user != null)
                m_user.Key = txtKey.Text;
        }

        private void chkBypassKey_CheckStateChanged(object sender, EventArgs e)
        {
            if (m_user != null)
                m_user.BypassKey = chkBypassKey.Checked;
        }

        private void txtDays_Validating(object sender, CancelEventArgs e)
        {
            int days;
            if (!Int32.TryParse(txtDays.Text, out days))
                e.Cancel = true;
            else if (m_user != null)
                m_user.AuthorizationDuration = new TimeSpan(days, m_user.AuthorizationDuration.Hours, m_user.AuthorizationDuration.Minutes, m_user.AuthorizationDuration.Seconds);
        }

        private void txtHours_Validating(object sender, CancelEventArgs e)
        {
            int hours;
            if (!Int32.TryParse(txtHours.Text, out hours))
                e.Cancel = true;
            else if (m_user != null)
                m_user.AuthorizationDuration = new TimeSpan(m_user.AuthorizationDuration.Days, hours, m_user.AuthorizationDuration.Minutes, m_user.AuthorizationDuration.Seconds);
        }

        private void txtMinutes_Validating(object sender, CancelEventArgs e)
        {
            int minutes;
            if (!Int32.TryParse(txtMinutes.Text, out minutes))
                e.Cancel = true;
            else if (m_user != null)
                m_user.AuthorizationDuration = new TimeSpan(m_user.AuthorizationDuration.Days, m_user.AuthorizationDuration.Hours, minutes, m_user.AuthorizationDuration.Seconds);
        }

        private void txtSeconds_Validating(object sender, CancelEventArgs e)
        {
            int seconds;
            if (!Int32.TryParse(txtSeconds.Text, out seconds))
                e.Cancel = true;
            else if (m_user != null)
                m_user.AuthorizationDuration = new TimeSpan(m_user.AuthorizationDuration.Days, m_user.AuthorizationDuration.Hours, m_user.AuthorizationDuration.Minutes, seconds);
        }

        #endregion

        #region Methods

        /// <summary>
        /// Define the invariant valid state for this class.
        /// </summary>
        [ContractInvariantMethod]
        private void InvariantValidState()
        {
            Contract.Invariant(!String.IsNullOrWhiteSpace(m_dataPath));
            Contract.Invariant(m_data != null);
            Contract.Invariant(m_log != null);
            Contract.Invariant(txtName != null);
            Contract.Invariant(txtIp != null);
            Contract.Invariant(chkBypassIp != null);
            Contract.Invariant(txtKey != null);
            Contract.Invariant(chkBypassKey != null);
            Contract.Invariant(txtDays != null);
            Contract.Invariant(txtHours != null);
            Contract.Invariant(txtMinutes != null);
            Contract.Invariant(txtSeconds != null);
            Contract.Invariant(lstUsers != null);
        }

        private void Reload()
        {
            Contract.Assume(m_data.User != null);
            lstUsers.DataSource = m_data.User;
            if (m_data.User.NameColumn != null)
            {
                lstUsers.DisplayMember = m_data.User.NameColumn.ColumnName;
                lstUsers.ValueMember = m_data.User.NameColumn.ColumnName;
            }
        }

        #endregion
    }
}
